home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / info-service / www / src / WWW / LineMode / Implementation / HTBrowse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-10  |  35.4 KB  |  1,346 lines

  1. /*    HyperText Browser for Dumb Terminals                  HTBrowse.c
  2. **    ====================================
  3. **
  4. **  Authors:
  5. **    NP:  Nicola Pellow  Tech.Student CERN 1990-91
  6. **    TBL: Tim Berners-Lee CERN (timbl@info.cern.ch)
  7. **    JFG: Jean-Francois Groff, Cooperant CERN 1991-92 (jfg@info.cern.ch)
  8. **    DR:  Dudu Rashty +972-2-584848 <RASHTY@hujivms.bitnet>
  9. **
  10. **  Copyright CERN 1990-1992   See Copyright.html 
  11. **
  12. **  History:
  13. **
  14. **   4 Dec 90:  Written from scratch (NP)
  15. **  11 Feb 91:  Code written by TBL so that the browser could be linked with
  16. **              code produced by Bernd Pollermann, enabling access to the
  17. **              data on CERNVM. This involved changing the code to handle file
  18. **              numbers rather than file pointers.
  19. **  18 Mar 91:  The feature of history mechanism was included, enabling a  
  20. **              record of previous nodes visited to be kept.
  21. **   6 Apr 91:  When a node is accessed, it is immediately read into a 
  22. **              buffer, in an unformatted state, as soon as the connection is   
  23. **              made, so that the server is freed as quickly as possible. 
  24. **              The program now also uses the additional modules HTBufferFile.c
  25. **              and HTBufferFile.h.
  26. **  17 Apr 91:  Can be used on machines running ANSI C and ordinary C.
  27. **  10 May 91:  Formatted text is stored in a linked list buffer which allows
  28. **              scrolling and better page breaks in the middle of text.
  29. **              Code incorporated by Tim BL, to enable anonymous FTP.          
  30. **  21 May 91:  Accepts various parameters on the command line.
  31. **  19 Aug 91:  Currently available in Unix, VAX/VMS and MVS environments.
  32. **  21 Nov 91:     Character grid uses new architecture. (TBL)
  33. **              added -w option, new commands, print,
  34. **                 ...    See Features.html for further details
  35. **  16 Jan 92:     Put in VIOLA-compatible options - see \017 characters.
  36. **                 \017 and \016 bracket user-selectable input.
  37. **  27 Feb 92:    New handling of user input, enhanced command syntax. (JFG)
  38. **  18 May 92:    PS command see ifdef SLAVE_PRINTER (DR/TBL)
  39. **   6 Oct 92:  Painful recovery from someone(?)'s attept to pretty print.(TBL)
  40. **        Please see coding style guide before changing indentation etc!
  41. **     Mar 93:    Force on HTFile's HTDirAccess and HTDirReadme flags.
  42. **
  43. ** Compilation-time macro options
  44. **
  45. **    REF_MARK    Printf string to be used for printing anchor numbers
  46. **    END_MARK    String to be used to denote the end of a document
  47. **    VL        Version number, quoted eg "1.2a"
  48. */
  49. #ifndef VL
  50. #define VL "unspecified"
  51. #endif
  52.  
  53. /*    If the guy gives the "MANUAL" command, jump to this:
  54. */
  55. #ifndef MANUAL
  56. #define MANUAL "http://info.cern.ch/hypertext/WWW/LineMode/Defaults/QuickGuide.html"
  57. #endif
  58.  
  59. /* Check Statements */
  60. /* ================ */
  61.  
  62. #define NAME_CHECK 0                /* Trace to show NAME anchors */
  63.  
  64.  
  65. /* Include Files */
  66. /* ============= */
  67.  
  68. #include <ctype.h>
  69. #include "HTUtils.h"            /* WWW general purpose macros */
  70.  
  71. #include "HTBrowse.h"         /* Things exported, short names */
  72.  
  73. #include "GridText.h"     /* Hypertext definition */
  74.  
  75. #include "HTFormat.h"
  76. #include "HTTCP.h"    /* TCP/IP utilities */
  77. #include "HTAnchor.h"   /* Anchor class */
  78. #include "HTParse.h"    /* WWW address manipulation */
  79. #include "HTAccess.h"   /* WWW document access network code */
  80. #include "HTHistory.h"    /* Navigational aids */
  81. #include "HTML.h"    /* For parser */
  82. #include "HTFWriter.h"    /* For non-interactive output */
  83. #include "HTFile.h"    /* For Dir access flags */
  84.  
  85. #ifdef THINK_C                     /* Macintosh Think C development system */
  86. #include <console.h>
  87. #include <time.h>
  88.     extern int socketdebug;  /* Must be declared in the socket library */
  89. #endif
  90.  
  91. extern HTStyleSheet * styleSheet;
  92.  
  93. /* Define Statements */
  94. /* ================= */
  95.  
  96. #ifndef REF_MARK        /* May be redefined on command line */
  97. #ifdef VIOLA
  98. #define REF_MARK "[\017%d\016]"    /* Shift-in, shift-out around number */
  99. #define PROMPT_MARK "\017%s\016"
  100. #else
  101. #define PROMPT_MARK "%s"
  102. #ifdef VM
  103. #define REF_MARK " <%d>"    /* IBM terminals can't handle [] well */
  104. #else
  105. #define REF_MARK "[%d]"
  106. #endif
  107. #endif
  108. #endif
  109.  
  110. #ifndef END_MARK
  111. #ifdef VM
  112. #define END_MARK "     <End>"
  113. #else
  114. #define END_MARK "     [End]"
  115. #endif
  116. #endif
  117.  
  118. #ifndef EOF
  119. #define EOF (-1)  /* End of file character defined as -1 */
  120. #endif
  121.  
  122.  
  123. #ifdef NEWLIB
  124. #define SCREEN_WIDTH 78
  125. #endif
  126.  
  127. #ifndef SCREEN_WIDTH      
  128. #define SCREEN_WIDTH 79  /* Default width of the screen */ 
  129. #endif
  130. #ifndef SCREEN_HEIGHT
  131. #define SCREEN_HEIGHT 24 /* Default number of lines to the screen */
  132. #endif
  133.  
  134. #ifdef VM               /* Needed to flush out the prompt line..*/
  135. #ifndef NEWLIB        /* except on NEWLIB which can wrap. */
  136. #define NEWLINE_PROMPT  /* before input */
  137. #endif
  138. #endif
  139.  
  140. #define INFINITY 1024                   /*!! BUG*/
  141. #define ADDRESS_LENGTH  INFINITY       /* Maximum address length of node */
  142. #define TITLE_LENGTH    INFINITY    /* Maximum length of a title */
  143. #define RESPONSE_LENGTH INFINITY    /* Maximum length of users response */
  144.  
  145.  
  146. /*    Public Variables
  147. **    ================
  148. */
  149.  
  150. PUBLIC char * HTAppName = "CERN-LineMode";    /* Application name */
  151. PUBLIC char * HTAppVersion = VL;     /* Application version */
  152.  
  153.  
  154. PUBLIC  int  HTScreenWidth   = SCREEN_WIDTH;    /* By default */
  155. PUBLIC  int  HTScreenHeight  = -1;             /* Undefined */
  156. PUBLIC  BOOL display_anchors = YES;             /* anchor will be shown in text? */
  157. PRIVATE  BOOL interactive     = YES;          /*  e.g. shows prompts etc */
  158. PRIVATE  char * output_file_name = NULL;     /* -o xxxx */
  159.                        
  160. PUBLIC char * reference_mark = REF_MARK;     /* Format string for [1] &c */
  161. PUBLIC char * end_mark = END_MARK;           /* Format string for [End] */
  162.  
  163. /* Moved into other files: */
  164.  
  165. /* PUBLIC char * HTClientHost = 0;      HTAccess */
  166. /* PUBLIC  int  WWW_TraceFlag   = 0;      HTString */
  167. /* PUBLIC FILE * logfile = 0;          HTAccess */
  168.  
  169.  
  170.  /*    Private variables
  171.  **    =================
  172.  */
  173. /* Arrays for storing the HyperText References */
  174.  
  175. PRIVATE HTParentAnchor * home_anchor = NULL;    /* First document anchor */
  176. PRIVATE char keywords[ADDRESS_LENGTH]; /* Search terms from command line */
  177.  
  178. PRIVATE char        choice[RESPONSE_LENGTH];    /* Users response  */
  179.  
  180. PRIVATE char *         logfile_root = 0;             /* Log file name */
  181. PUBLIC char *         log_file_name = 0;             /* Root of log file name */
  182. PRIVATE BOOL         filter=0;                       /* Load from stdin? */
  183. PRIVATE BOOL         listrefs_option = 0;    /* -listrefs option used?  */
  184.  
  185. /* Forward Declaration of Functions */
  186. /* ================================ */
  187.  
  188. PRIVATE void History_List NOPARAMS; 
  189. PRIVATE void Selection_Prompt NOPARAMS;
  190. /* PRIVATE BOOL Check_User_Input PARAMS((char *s)); */
  191. PRIVATE void Error_Selection NOPARAMS;
  192. PRIVATE void help_screen NOPARAMS;
  193. PRIVATE void Reference_List PARAMS((BOOL titles));
  194.  
  195. PRIVATE HTFormat HTInputFormat = NULL;
  196.  
  197. /* MAIN PROGRAM
  198. ** ------------
  199. */
  200.  
  201. int main
  202. #ifdef __STDC__
  203.         (int argc, char * argv[])
  204. #else
  205.         (argc, argv)
  206.             int argc;
  207.             char * argv[];
  208. #endif
  209.  
  210. {
  211.     int  arg;                 /* Argument number as we scan */
  212.     BOOL argument_found = NO;
  213.     BOOL first_keyword = YES;
  214.     BOOL default_used = NO;     /* Fell back on home page? */
  215.     char* default_default=0;     /* Parse home relative to this */
  216.  
  217.     HTFormat format_in = WWW_HTML;        /* By default */
  218.     HTOutputFormat = WWW_PRESENT;            /* By default */
  219.     
  220. #ifdef THINK_C /* command line from Think_C */
  221.     int i;
  222.     argc=ccommand(&argv);
  223. #endif
  224.     
  225.     StrAllocCopy(default_default, "file://");
  226.     StrAllocCat(default_default, HTHostName()); /* eg file://cernvax.cern.ch */
  227.  
  228. #ifndef MAXPATHLEN
  229. #define NO_GETWD        /* Assume no  getwd() if no MAXPATHLEN */
  230. #endif
  231.  
  232. #ifdef NO_GETWD          /* No getwd() on this machine */
  233. #ifdef HAS_GETCWD        /* System V variant SIGN CHANGED TBL 921006 !! */
  234.  
  235.     {
  236.     char wd[1024];            /*!! Arbitrary*/
  237.     extern char * getcwd();
  238.     char * result = getcwd(wd, sizeof(wd)); 
  239.     if (result) {
  240.  
  241. #ifdef vms  /* convert directory name to Unix-style syntax */
  242.         char * disk = strchr (wd, ':');
  243.         char * dir = strchr (wd, '[');
  244.         if (disk) {
  245.             *disk = '\0';
  246.         StrAllocCat (default_default, "/");  /* needs delimiter */
  247.         StrAllocCat (default_default, wd);
  248.         }
  249.         if (dir) {
  250.         char *p;
  251.         *dir = '/';  /* Convert leading '[' */
  252.         for (p = dir ; *p != ']'; ++p)
  253.             if (*p == '.') *p = '/';
  254.         *p = '\0';  /* Cut on final ']' */
  255.         StrAllocCat (default_default, dir);
  256.         }
  257. #else  /* not VMS */
  258.         StrAllocCat (default_default, wd);
  259. #endif  /* not VMS */
  260.         } else {
  261.             fprintf(stderr,
  262.             "HTBrowse: Can't read working directory (getcwd).\n");
  263.         }
  264.     }  /* end if good getcwd result */
  265.     
  266. #else   /* has NO getcwd */
  267.  
  268.     if (TRACE) fprintf(stderr,
  269.         "HTBrowse: This platform does not support getwd() or getcwd()\n");
  270. #endif    /* has no getcwd */
  271.  
  272. #else   /* has getwd */
  273.     {
  274.               char wd[MAXPATHLEN];
  275.         extern char * getwd();
  276.               char * result = getwd(wd);
  277.         if (result) {
  278.             StrAllocCat(default_default, wd);
  279.         } else {
  280.             fprintf(stderr, "HTBrowse: Can't read working directory.\n");
  281.         }
  282.     }
  283. #endif
  284.         
  285. #ifdef vms
  286.       StrAllocCat(default_default, "default.html");
  287. #else
  288.       StrAllocCat(default_default, "/default.html");
  289. #endif
  290.  
  291. /*    Check for command line options
  292. **    ------------------------------
  293. */
  294.  
  295.     keywords[0] = 0;                /* Clear string */
  296.     for (arg=1; arg<argc ; arg++) {
  297.     if (*argv[arg]=='-'){
  298.         
  299. #ifdef TRACE
  300.        /* Verify: Turns on trace */
  301.         if (0==strcmp(argv[arg], "-v")) {
  302.         WWW_TraceFlag = 1;
  303.         }
  304. #endif
  305.     
  306.         /* - alone => filter */
  307.         else if (argv[arg][1] == 0) {
  308.         filter = YES;       
  309.         /* Take from stdin, Force non-interactive */
  310.         interactive = NO;
  311.         
  312.         /* Page size */
  313.         } else if (argv[arg][1] == 'p') {
  314.         if (sscanf(argv[arg]+2, "%d", &HTScreenHeight) <1)  /* fail */
  315.             HTScreenHeight = -1;       /* Undefined */
  316.         
  317.         /* Page width */
  318.         } else if (argv[arg][1] == 'w') {
  319.         if (sscanf(argv[arg]+2, "%d", &HTScreenWidth) <1)  /* fail */
  320.             HTScreenWidth = SCREEN_WIDTH;
  321.         
  322.         /* from -- Initial represntation */
  323.         } else if (0==strcmp(argv[arg], "-from")) {
  324.         if (++arg < argc)
  325.             HTInputFormat = HTAtom_for(argv[arg]);
  326.  
  327.         /* Telnet from */
  328.         } else if (argv[arg][1] == 'h') {
  329.         if (++arg < argc)
  330.             HTClientHost = argv[arg]; /* Use original host name */
  331.  
  332.             
  333.         /* Log file */
  334.         } else if (0==strcmp(argv[arg], "-l")) {
  335.         if (++arg <argc) {
  336.             logfile_root = argv[arg];
  337.         }
  338.             
  339.         /* Log file */
  340.         } else if (0==strcmp(argv[arg], "-listrefs")) {
  341.         listrefs_option = YES;
  342.         interactive = NO;    /* Force non-interactive */
  343.  
  344.         /* Non-interactive */
  345.         } else if (0==strcmp(argv[arg], "-n")) {
  346.         interactive = NO;
  347.  
  348.         /* Output filename */
  349.         } else if (0==strcmp(argv[arg], "-o")) { 
  350.         if (++arg < argc) {
  351.             output_file_name = argv[arg];/* Change representation */
  352.             interactive = NO;
  353.         }
  354.         /* Anchor format */
  355.         } else if (0==strcmp(argv[arg], "-a")) { 
  356.         if (++arg < argc)
  357.             reference_mark = argv[arg];      /* Change representation */
  358.  
  359.         /* No anchors */
  360.         } else if (0==strcmp(argv[arg], "-na")) { 
  361.             display_anchors = NO;
  362.  
  363. #ifndef NO_RULES
  364.         } else if (0==strcmp(argv[arg], "-r")) {
  365.             if (++arg<argc) { 
  366.             if (HTLoadRules(argv[arg]) < 0) exit(-1);
  367.         }
  368. #endif
  369. #ifndef NO_DIR_OPTIONS
  370.         } else if (0==strncmp(argv[arg], "-d", 2)) {
  371.             char *p = argv[arg]+2;
  372.         for(;*p;p++) {
  373.             switch (argv[arg][2]) {
  374.             case 'b':    HTDirReadme = HT_DIR_README_BOTTOM; break;
  375.             case 'n':    HTDirAccess = HT_DIR_FORBID; break;
  376.             case 'r':    HTDirReadme = HT_DIR_README_NONE; break;
  377.             case 's':   HTDirAccess = HT_DIR_SELECTIVE; break;
  378.             case 't':    HTDirReadme = HT_DIR_README_TOP; break;
  379.             case 'y':    HTDirAccess = HT_DIR_OK; break;
  380.             default:
  381.             fprintf(stderr, 
  382.                "HTDaemon: bad -d option %s\n", argv[arg]);
  383.             exit(-4);
  384.             }
  385.         } /* loop over characters */
  386. #endif
  387.         /* Source please */
  388.         } else if (0==strcmp(argv[arg], "-source")) {
  389.             HTOutputFormat = WWW_SOURCE;
  390.             HTOutputSource = YES;    /* Turn on shortcut */
  391.             interactive = NO;    /* JFG */
  392.             
  393.         /* to -- Final represntation */
  394.         } else if (0==strcmp(argv[arg], "-to")) {
  395.         if (++arg < argc) {
  396.             HTOutputFormat = HTAtom_for(argv[arg]);
  397.             HTOutputSource = YES;    /* Turn on shortcut */
  398.             interactive = NO;    /* JFG */
  399.         }
  400.         /* Print version and exit */
  401.         } else if (0==strcmp(argv[arg], "-version")) { 
  402.             printf("WWW LineMode Browser version %s (WWW Library %s)\n",
  403.                 VL, HTLibraryVersion);
  404.         exit(0);
  405.         }
  406. #ifdef THINK_C
  407.         /* Echo to file */
  408.         else if (0==strcmp(argv[arg], "-e")){
  409.         struct tm *tm_now; time_t time_now;
  410.         cecho2file("ThinkCconsole",FALSE,stdout);
  411.         time_now=time(NULL);tm_now=localtime(&time_now);
  412.         printf("\n--------------------------------------------"
  413.             "\n Time: %d.%.2d.%.2d %d:%d:%d\n"
  414.             "--------------------------------------------\n",
  415.             (*tm_now).tm_year,
  416.             (*tm_now).tm_mon+1,
  417.             (*tm_now).tm_mday,
  418.             (*tm_now).tm_hour,
  419.             (*tm_now).tm_min,
  420.             (*tm_now).tm_sec);
  421.     
  422.         /* debug socket library */
  423.         } else if (0==strcmp(argv[arg], "-s")) {
  424.             socketdebug=1;
  425.         }
  426. #endif
  427.           /* endif long list of argument options */
  428.  
  429.     } else {  /* it doesn't start with a dash */
  430.  
  431. /*      Check for main argument
  432. **      -----------------------
  433. */
  434.             if (!argument_found) {
  435.         char * ref = HTParse(argv[arg], default_default, PARSE_ALL);
  436.         home_anchor = (HTParentAnchor*)HTAnchor_findAddress(ref);
  437.         free(ref);
  438.         argument_found = YES;
  439.             
  440.  
  441. /*      Check for successive keyword arguments
  442. **      -------------------------------------
  443. */
  444.         } else {   /* Argument already found */
  445.         /* Collect keywords */
  446.         if (first_keyword){
  447.             first_keyword = NO;
  448.         } else {
  449.             strcat(keywords, " ");
  450.         }
  451.         strcat(keywords,HTStrip(argv[arg]));
  452.  
  453.         } /* argument already found */
  454.     } /* Not an option '-'*/
  455.     } /* End of argument loop */
  456.  
  457.     if (HTScreenHeight == -1)        /* Default page size */
  458.     HTScreenHeight = interactive ? SCREEN_HEIGHT : 999999;
  459.  
  460. /*    Open output file
  461. **    ----------------
  462. */
  463.     if (!interactive)    {        /* check for file name @@@@@ */
  464.         if (output_file_name) {
  465.         FILE * fp = fopen(output_file_name, "w");
  466.         if (!fp) {
  467.             fprintf(stderr, "WWW: Can't open file `%s' for writing\n",
  468.             output_file_name);
  469.         exit(-4);
  470.         }
  471.             HTOutputStream = HTFWriter_new(fp);   /* Out to file */
  472.     } else {
  473.             HTOutputStream = HTFWriter_new(stdout);   /* Just pump to stdout */
  474.     }
  475.     }
  476.     
  477.     
  478. /*    Open Log File if necessary
  479. **    --------------------------
  480. */
  481.     if (!logfile_root && HTClientHost) {
  482.     logfile_root = DEFAULT_LOGFILE;
  483.     }
  484.     
  485.         
  486.     if (logfile_root) {
  487.     log_file_name = (char*) malloc(strlen(logfile_root)+20);
  488. #ifdef NO_GETPID
  489.     sprintf(log_file_name, "%s", logfile_root);  /* No getpid() */
  490. #else
  491.     sprintf(log_file_name, "%s-%d", logfile_root, getpid());
  492. #endif
  493.     logfile = fopen(log_file_name, "a");
  494.     if (!logfile)
  495.         fprintf(stderr, "WWW: Can't open log file %s\n",log_file_name);
  496.     };
  497.  
  498.  
  499. /*    Enable local directory access
  500. */
  501.     HTDirReadme = HT_DIR_README_TOP;    /* Readme presentation */
  502.     HTDirAccess = HTClientHost ? HT_DIR_SELECTIVE : HT_DIR_OK;    /* browsing */
  503.     
  504.  
  505. /*    Make home page address
  506. **    ----------------------
  507. */    
  508.     if (!home_anchor)
  509.     home_anchor = HTHomeAnchor ();
  510.     
  511.  
  512. /*    Non-interactive use
  513. **    -------------------
  514. */
  515.  
  516.     if (filter) {            /* Just convert formats */
  517.         HTParseSocket(format_in, HTOutputFormat, 
  518.                 home_anchor,
  519.         0,            /* stdin unix file */
  520.         HTOutputStream);
  521.         goto good;
  522.     }
  523.     
  524. /*    Load first document
  525. **    -------------------
  526. */
  527.     if ( *keywords ? HTSearch(keywords, home_anchor)
  528.                : HTLoadAnchor((HTAnchor*)home_anchor)){
  529.            
  530.     HTHistory_record((HTAnchor *)home_anchor);
  531.     
  532.     } else {    /* Can't even get last resort: give up */
  533.     
  534.     fprintf(stderr, "\nWWW: Can't access `%s'\n", 
  535.         HTAnchor_address((HTAnchor *)home_anchor));/* not freed */
  536.     if (!HTMainText) exit(2); /* Can't get first page */
  537.     }
  538.     
  539.     if (!HTMainText) exit(0);    /* Hypertext object was not created */
  540.     
  541. /*     Main "Event Loop"
  542. **    ----------------
  543. */
  544.  
  545.     if (interactive) {
  546.     while (YES) Selection_Prompt();
  547.     
  548.     } else if (!HTOutputSource) {    /* Non-interactive but formatted */
  549.     printf("\f");            /* Form feed for new page */
  550.     while(HText_canScrollDown(HTMainText)) {
  551.         HText_scrollDown(HTMainText);
  552.         printf("\f");        /* Form feed for new page */
  553.     }
  554.     
  555.     if (listrefs_option) {
  556.         Reference_List(NO);        /* List without titles */
  557.     }
  558.     }
  559. good:    
  560. #ifdef vms
  561.     return 1;
  562. #else
  563.     return 0; /* Good */
  564. #endif
  565.  
  566. } /* main() */
  567.  
  568.  
  569.  
  570. /*    Error_Selection
  571. **    ---------------
  572. ** Produce an error message.
  573. **
  574. */                       
  575.  
  576. #ifdef __STDC__
  577. PRIVATE void Error_Selection(void)
  578. #else
  579. PRIVATE void Error_Selection()
  580. #endif
  581.  
  582. {    
  583.     fprintf(stderr, "%s", "Bad command, for list of commands type help.\n");
  584.     return;
  585. }
  586.  
  587.  
  588. /*        Display Help screen                     Help_screen
  589. **        -------------------
  590. **
  591. ** Produce a help screen, displaying the current document address and a list of 
  592. ** available commands *in this context*.
  593. ** ?? Perhaps this should be a hypertext page, not included in the history list.
  594. */
  595.  
  596. PRIVATE void help_screen NOARGS {
  597.  
  598.     char * current_address = HTAnchor_address((HTAnchor*)HTMainAnchor);
  599.     CONST char * title = HTAnchor_title(HTMainAnchor);
  600.     
  601.     printf("\n\nWWW LineMode Browser version %s (WWWLib %s)   COMMANDS AVAILABLE\n\n",
  602.                 VL, HTLibraryVersion);
  603.     if (title) printf("You are reading\n \"%s\"\nwhose address is\n  %s\n\n",
  604.                             title, current_address);
  605.     else printf("You are reading a document whose address is\n    '%s' \n\n",
  606.                     current_address);
  607.     
  608.     if (HText_canScrollDown(HTMainText)) {
  609.     printf(
  610.         "  <RETURN>        Move down one page within the document.\n");
  611.     printf(
  612.         "  BOttom          Go to the last page of the document.\n");
  613.     };
  614.         
  615.     if (HText_canScrollUp(HTMainText)) {
  616.     printf(
  617.         "  Top             Return to the first page of the document.\n");
  618.     printf(
  619.         "  Up              Move up one page within the document\n");
  620.     };
  621.         
  622.     if (HText_sourceAnchors(HTMainText) != 0) {
  623.     printf("  List            List the references from this document.\n");
  624.     printf("  <number>        Select a referenced document by number (from 1 to %d).\n",
  625.         HText_sourceAnchors(HTMainText));
  626.     }
  627.         
  628.     if (HTAnchor_isIndex(HTMainAnchor)) {
  629.     printf(
  630.         "  Find <words>    Search this index for given words (separated by spaces).\n"); 
  631.     }
  632.         
  633.     if (HTHistory_canBacktrack()) {
  634.     printf("  Recall          List visited documents.\n");
  635.     printf("  Recall <number> Return to a previously visited document\n");
  636.     printf("                  as numbered in the recall list.\n");
  637.     printf("  HOme            Return to the starting document.\n");
  638.     printf("  Back            Move back to the last document.\n");
  639.     }
  640.         
  641.     if (HTHistory_canMoveBy(1))
  642.         printf("  Next            Take next link from last document.\n");
  643.             
  644.     if (HTHistory_canMoveBy(-1))
  645.         printf("  Previous        Take previous link from last document.\n");
  646.  
  647.     printf("  Go address      Go to document of given [relative] address\n");
  648.         
  649. #ifdef GOT_SYSTEM
  650.     if (!HTClientHost) {    /* NOT for telnet guest! */
  651.         printf("  PRInt           Print text of this document. *\n");
  652.         printf("  ! command       Execute shell command without leaving.\n");
  653.         printf("  > file          Save the text of this document in a file. *\n");
  654.         printf("  >> file         Append the text of this document to a file. *\n");
  655.         printf("  | command       Pipe this document to a shell command. *\n");
  656. #ifdef unix
  657.         printf("  CD directory    Change local working directory.\n");
  658. #endif
  659.         printf("* Prefix these commands with \"Source \" to use raw source.\n\n");
  660.     }
  661. #endif
  662.         
  663. #ifdef SLAVE_PRINTER
  664.     printf(
  665.     "  Ps              Print text of this document to Terminal's Slave printer.\n");
  666. #endif
  667.         
  668.     printf("  Verbose         Switch to %sverbose mode.\n", WWW_TraceFlag ? "non-" : "");
  669.         
  670.     printf("  Help            Display this page.\n");
  671.     printf("  Manual          Jump to the online manual for this program\n");
  672.     printf("  Quit            Leave the www program.\n");
  673.         
  674.     printf("\n");
  675.     
  676.     free(current_address);
  677.     
  678. }
  679.  
  680.  
  681. /*        Select_Reference
  682. **        ----------------
  683. **
  684. **  After a reference is selected by the user, opens document, links into the history
  685. **  list and displays.
  686. **
  687. **  On Entry:
  688. **       int  reference_num   Number corresponding to the hypertext reference
  689. **                            given in the text.
  690. */
  691.  
  692. BOOL Select_Reference ARGS1(int,reference_num) {
  693.  
  694.     HTAnchor         * destination;
  695.     HTChildAnchor * source = HText_childNumber(HTMainText, reference_num);
  696.     
  697.     if (!source) return NO; /* No anchor */
  698.     destination = HTAnchor_followMainLink((HTAnchor*) source);
  699.     if (!HTLoadAnchor(destination)) return NO;    /* No link */
  700.     HTHistory_leavingFrom((HTAnchor*) source);
  701.     HTHistory_record(destination);
  702.     
  703.     return YES;
  704.     
  705. } /* Select_Reference*/
  706.  
  707.  
  708. /*     Reference_List
  709. **    --------------
  710. **      Print out a list of HyperText References accumulated within the text.
  711. **
  712. ** On entry
  713. **    titles        Set:    if we want titles where available
  714. **            Clear:  we only get addresses.
  715. */
  716.  
  717. PRIVATE void Reference_List ARGS1(BOOL, titles)
  718.  
  719. {
  720.     int  n;
  721.     
  722.     if (HText_sourceAnchors(HTMainText) == 0) {
  723.         printf("\n\n     There are no references from this document.\n\n");
  724.     } else {
  725.         
  726.     printf("\n\n     References from this document:-\n\n");
  727.         
  728.     for (n=1; n<=HText_sourceAnchors(HTMainText); n++) {
  729.         HTAnchor * destination =
  730.         HTAnchor_followMainLink(
  731.             (HTAnchor *)HText_childNumber(HTMainText, n)
  732.             );
  733.         HTParentAnchor * parent = HTAnchor_parent(destination);
  734.         char * address =  HTAnchor_address(destination);
  735.         CONST char * title = titles ? HTAnchor_title(parent) : 0 ;
  736.  
  737.         printf(reference_mark, n);
  738.         printf("  %s%s\n",
  739.             ((HTAnchor*)parent!=destination) && title ? "in " : "",
  740.             (char *)(title ? title : address));
  741.         free(address);
  742.     }
  743.         
  744.     printf("\n");
  745.     }
  746. }      
  747.  
  748.  
  749. /*        History_List
  750. **        ------------
  751. */
  752. /*    Display a history list of nodes visited during the session.
  753. **    ?? This should really be a hypertext page (not itself in history!).
  754. **    ?? Should have option to display address even when anchor has a title.
  755. */
  756.  
  757. PRIVATE void History_List NOARGS {
  758.  
  759.     int  history_number = 1; 
  760.     printf("\n  Documents you have visited:-\n\n");
  761.     
  762.     do {
  763.     
  764.     char * address;
  765.     CONST char * title;
  766.     HTAnchor * anchor = HTHistory_read(history_number);
  767.     HTParentAnchor * parent;
  768.     
  769.     if (!anchor) break;
  770.     parent = HTAnchor_parent(anchor);
  771.     title = HTAnchor_title(parent);
  772.     address = HTAnchor_address(anchor);
  773. #ifdef VIOLA
  774.     printf("\017R %2d\016)   %s%s\n",    /* SI user field SO */
  775. #else
  776.     printf("R %2d)   %s%s\n",
  777. #endif
  778.         history_number,
  779.         ((HTAnchor*)parent!=anchor) && title ? "in " : "",
  780.         title ? title : address);
  781.     free(address);
  782.     
  783.     history_number++;
  784.     
  785.     } while (YES);
  786.  
  787.     printf("\n");
  788. }      
  789.  
  790.  
  791. /*
  792. **    Check_User_Input
  793. **    ----------------
  794. **
  795. ** Accepts shortened versions of commands.
  796. **
  797. **  On Entry:
  798. **       char *s  Correct and full version of command, to which the user's 
  799. **                input is compared.
  800. **
  801. **  On Exit:
  802. **         returns  YES  User's input corresponds to the command.
  803. **                   NO  Not a recognized command.  
  804. */
  805.  
  806. #define Check_User_Input(command) \
  807.     (!strncasecomp (command, this_word, strlen(this_word)))
  808.  
  809.  
  810. /*            USER INTERFACE
  811. **            ==============
  812. */
  813.  
  814. /* Selection_Prompt
  815. ** ----------------
  816. ** Produces a prompt at the bottom of a page full of text. The prompt varies 
  817. ** depending on the options avaliable.
  818. */
  819.  
  820. #ifdef __STDC__
  821. PRIVATE void Selection_Prompt(void)
  822. #else
  823. PRIVATE void Selection_Prompt()
  824. #endif
  825.  
  826.     BOOL HTDiag = NO;    /* Flag == source asked for? */    
  827.     int length_of_prompt = 0;
  828.     BOOL is_index = HTAnchor_isIndex(HTMainAnchor);
  829.     
  830.     if ( !HText_canScrollDown(HTMainText) &&
  831.             !HTAnchor_hasChildren(HTMainAnchor) &&
  832.             !is_index && 
  833.             (!HTHistory_canBacktrack())){
  834.         printf("\n");
  835.         
  836.         exit(0); /* Exit if no other options */
  837.     }
  838.     
  839.     HText_setStale(HTMainText);    /* We corrupt the display */
  840.     
  841. #ifndef VM    /* Normal prompt */
  842.         
  843.         if (is_index){    
  844.             printf("FIND <keywords>, ");
  845.             length_of_prompt = length_of_prompt + 14;
  846.             }
  847.         if (HTAnchor_hasChildren(HTMainAnchor)!=0){
  848.             int refs = HText_sourceAnchors(HTMainText);
  849.             if (refs>1) {
  850.                 printf("1-%d, ", refs);
  851.                 length_of_prompt = length_of_prompt + 6;    /* Roughly */
  852.                 }
  853.             else {
  854.                 printf("1, ");    
  855.                 length_of_prompt = length_of_prompt + 3;
  856.                 }
  857.             }
  858.             
  859.         if (HTHistory_canBacktrack()){
  860.             printf(PROMPT_MARK, "Back"); printf(", ");
  861. #ifdef LONG_PROMPT
  862.             printf(PROMPT_MARK, "Recall"); printf(", ");
  863. #endif
  864.             length_of_prompt = length_of_prompt + 6;
  865.             }
  866.         if (HText_canScrollUp(HTMainText)){
  867.             printf(PROMPT_MARK,"Up"); printf(", ");
  868.             length_of_prompt = length_of_prompt + 4;
  869.             }
  870.         if (HText_canScrollDown(HTMainText)){
  871.             printf("<RETURN> for more, ");
  872.             length_of_prompt = length_of_prompt + 19;
  873.             }
  874.         if (length_of_prompt <= 47){
  875.             printf(PROMPT_MARK, "Quit"); printf(", ");
  876.             }
  877.  
  878.         printf("or Help: ");    
  879.     
  880. #else    /* Special prompt for VM assuming PF keys set*/
  881.         if (is_index){    
  882.             printf("FIND <words>, ");            /*    14    */
  883.             length_of_prompt = length_of_prompt + 14;
  884.             }
  885.         if (HTAnchor_hasChildren(HTMainAnchor)!=0){
  886.             int refs = HText_sourceAnchors(HTMainText);
  887.             if (refs>1) {
  888.                 printf("1-%d, ", refs);
  889.                 length_of_prompt = length_of_prompt + 6;    /* approx 6    */
  890.                 }
  891.             else {
  892.                 printf("1, ");
  893.                 length_of_prompt = length_of_prompt + 3;
  894.                 }
  895.             }
  896.         if (HTHistory_canMoveBy(1)) {
  897.             printf("PF2=Next ");
  898.             length_of_prompt = length_of_prompt + 9; /* 9 */
  899.             }
  900.         printf("PF3=Quit PF4=Return, ");
  901.         length_of_prompt = length_of_prompt + 21;  /*21    */
  902.         
  903.         if (HTHistory_canBacktrack()){
  904.             printf("Recall, ");
  905.             length_of_prompt = length_of_prompt + 8; /* 8*/
  906.             }
  907.         if (HText_canScrollUp(HTMainText)){
  908.             printf(PROMPT_MARK,"PF7=Up "); printf(", ");
  909.             length_of_prompt = length_of_prompt + 7; /* 7 */
  910.             }
  911.         if (HText_canScrollDown(HTMainText)){
  912.             printf("PF8=Down ");
  913.             length_of_prompt = length_of_prompt + 9; /* 9 */
  914.             }
  915.         if (length_of_prompt<70) printf("PF11=Help");    /* 9 */
  916.         /* ------    */
  917.         /*     82     */
  918. #endif
  919.  
  920.     
  921. /* Read in the user's input, and deal with it as necessary.
  922. **
  923. **    Any Command which works returns from the routine. If nothing
  924. **    works then a search or error message down at the bottom.
  925. */
  926.     
  927.     {   
  928.     int  reference_num;
  929.     char * the_choice = 0;        /* preserved user command */
  930.     char * this_word;           /* First word of command */
  931.     char * this_command;        /* this_word and following */
  932.     char * next_word;           /* Second word */
  933.     char * other_words;           /* Second word and following */
  934.     
  935.     
  936. #ifdef NEWLINE_PROMPT
  937.     printf("\n");  /* For use on VM to flush out the prompt */ 
  938. #endif
  939.     fgets(choice, RESPONSE_LENGTH, stdin);    /* Read User Input */
  940.     StrAllocCopy (the_choice, choice);     /* Remember it as is, */
  941.     if (the_choice[strlen(the_choice)-1] == '\n')  /* except the final \n */
  942.        the_choice[strlen(the_choice)-1] = '\0';
  943.     
  944. #ifdef VM  /* Clear the screen (on screen-mode systems) */
  945.     clear_screen();
  946. #endif
  947.     
  948.     this_word = strtok (choice, " \t\n\r");  /* Tokenize user input */
  949.     this_command = the_choice;
  950.     if (this_word) {
  951.         next_word = strtok (NULL, " \t\n\r");
  952.         other_words = the_choice + (next_word - choice);
  953.         }
  954.     else
  955.         goto down;  /* Empty input : scroll down */
  956.  
  957.  
  958. /*        Process Command
  959. **        ---------------
  960. */
  961. /* Giant switch for incoming commands, many of which are single-letter.
  962. */
  963. loop:
  964.  
  965.     switch (TOUPPER(*this_word)) {
  966.  
  967.     case '0':
  968.     case '1':
  969.     case '2':
  970.     case '3':
  971.     case '4':
  972.     case '5':
  973.     case '6':
  974.     case '7':
  975.     case '8':
  976.     case '9':
  977.         sscanf(this_word,"%d",&reference_num);
  978.         if ((reference_num >= 1)&&
  979.             (reference_num <= HText_sourceAnchors(HTMainText))){
  980.                                                                             /* Selection of a reference */
  981.                 Select_Reference(reference_num);
  982.                 goto ret;
  983.                 }            
  984.         break;
  985.  
  986.  
  987.  
  988.  
  989.     case 'B':        
  990.         if (Check_User_Input("BACK")) { /* Return to previous node if this is possible */
  991.             if (!HTHistory_canBacktrack()){
  992.                 printf("\n  The BACK command cannot be used,");
  993.                 printf(" as there are no previous documents\n");
  994.                 goto ret; 
  995.                 }
  996.             HTLoadAnchor(HTHistory_backtrack());
  997.             goto ret;
  998.             }
  999.         else if (Check_User_Input("BOTTOM")) { /* Scroll to bottom  */
  1000.             HText_scrollBottom(HTMainText);
  1001.             goto ret;
  1002.             }
  1003.         break;
  1004.  
  1005.  
  1006.  
  1007.  
  1008. #ifdef unix
  1009.         case 'C':
  1010.             if (Check_User_Input("CD"))
  1011.                 /* Change working directory ? */
  1012.                 goto lcd;
  1013.             break;
  1014. #endif
  1015.  
  1016.  
  1017.  
  1018.  
  1019.     case 'D':
  1020.         if (Check_User_Input("DOWN")) { /* Scroll down one page  */
  1021. down:
  1022.             if (HText_canScrollDown(HTMainText))
  1023.                 HText_scrollDown(HTMainText);
  1024.             goto ret;
  1025.             }
  1026.         break;
  1027.  
  1028.  
  1029.  
  1030.  
  1031.     case 'E': /* Quit program ? Alternative command */
  1032.         if (Check_User_Input("EXIT"))
  1033.             exit(0);
  1034.         break;
  1035.  
  1036.  
  1037.  
  1038.  
  1039.     case 'F':
  1040.         if (is_index && Check_User_Input("FIND")){ /* Keyword search ? */
  1041. find:
  1042.             if (HTSearch(other_words, HTMainAnchor))
  1043.                 HTHistory_record((HTAnchor*)HTMainAnchor);
  1044.             goto ret;
  1045.             }
  1046.         break;
  1047.  
  1048.  
  1049.  
  1050.  
  1051.     case 'G':
  1052.     if (Check_User_Input("GOTO")){ /* GOTO */
  1053.         if (HTLoadRelative(next_word, HTMainAnchor))
  1054.             HTHistory_record((HTAnchor*)HTMainAnchor);
  1055.         goto ret;
  1056.         }
  1057.     break;
  1058.     
  1059.     case '?':
  1060.         help_screen();
  1061.         goto ret;
  1062.  
  1063.     case 'H':
  1064.         if (Check_User_Input("HELP")){  /* help menu, ..*/
  1065.             help_screen();                /*!! or a keyword search ? */
  1066.             goto ret; 
  1067.             }
  1068.     
  1069.         else if (Check_User_Input("HOME")){ /* back HOME */
  1070.             if (!HTHistory_canBacktrack()){ 
  1071.                 HText_scrollTop(HTMainText);
  1072.                 } 
  1073.             else {
  1074.                 HTLoadAnchor(HTHistory_recall(1)); /*!! this assumes history is kept.*/
  1075.                 }
  1076.             goto ret;
  1077.             } /* if HOME */
  1078.         break;
  1079.  
  1080.  
  1081.  
  1082.  
  1083.     case 'K':                                /* Keyword search ? */
  1084.         if (is_index && Check_User_Input("KEYWORDS")){
  1085.             goto find;
  1086.             }
  1087.         break;
  1088.  
  1089.  
  1090.  
  1091.  
  1092.     case 'L':
  1093.         if (Check_User_Input("LIST")){      /* List of references ? */
  1094.             Reference_List(!HTDiag);
  1095.             goto ret;
  1096.         }
  1097. #ifdef unix
  1098.             else if (Check_User_Input ("LCD")) {  /* Local change dir ? */
  1099. lcd:          if (!next_word) {  /* Missing argument */
  1100.                     printf ("\n  Please specify the name of the new local directory.\n");
  1101.                     goto ret;
  1102.                     }
  1103.                 if (chdir (next_word)) {  /* failed : say why */
  1104.                     fprintf (stderr, "\n  ");
  1105.                     perror (next_word);
  1106.                     }
  1107.                 else {  /* Success : display new local directory */
  1108.                     printf ("\n  Local directory is now:\n    %s\n", getwd (choice));
  1109.                     }
  1110.                 goto ret;
  1111.                 }
  1112. #endif
  1113.         break;
  1114.  
  1115.  
  1116.     case 'M':
  1117.     if (Check_User_Input("MANUAL")){     /* Read User manual */
  1118.         if (HTLoadRelative(MANUAL, HTMainAnchor))
  1119.             HTHistory_record((HTAnchor*)HTMainAnchor);
  1120.         goto ret;
  1121.         }
  1122.     break;
  1123.     
  1124.  
  1125.  
  1126.     case 'N':                    
  1127.         if (Check_User_Input("NEXT")) {
  1128.             if (!HTHistory_canMoveBy(1)){   /* No nodes to jump back to */
  1129.                 printf("\n  Can't take the NEXT link from the last");
  1130.                 if (!HTHistory_canBacktrack())
  1131.                 printf(" document as there is no last");
  1132.                 printf(" document.\n");
  1133.                 goto ret; 
  1134.                 }
  1135.             HTLoadAnchor(HTHistory_moveBy(1));
  1136.             goto ret;
  1137.             }
  1138.         break;
  1139.  
  1140.  
  1141.  
  1142.  
  1143.     case 'P':                    
  1144.         if (Check_User_Input("PREVIOUS")) {
  1145.             if (!HTHistory_canMoveBy(-1)){ 
  1146.                 printf("\n  Can't take the PREVIOUS link from the last");
  1147.                 if (!HTHistory_canBacktrack())
  1148.                     printf(" document as there is no last");
  1149.                 printf(" document.\n");
  1150.                 goto ret;
  1151.                 }
  1152.             HTLoadAnchor(HTHistory_moveBy(-1));
  1153.             goto ret;
  1154.             }
  1155. #ifdef GOT_SYSTEM        
  1156.             else if (!HTClientHost && Check_User_Input("PRINT")) {
  1157.                 char * address = HTAnchor_address((HTAnchor*)HTMainAnchor);
  1158.                 char * command;
  1159.                 char * template = (char*)getenv("WWW_PRINT_COMMAND");
  1160.                 int result;
  1161.             
  1162.                 if (!template) template = "www -n -na -p66 '%s' | lpr";
  1163.                 command  = (char *) malloc(strlen(address)+strlen(template)+20);
  1164.                 sprintf(command, template, address);
  1165.                 result = system(command);
  1166.                 free(address);
  1167.                 free(command);
  1168.                 if (result) printf("  %s\n  returns %d\n", command, result);
  1169.                 goto ret;
  1170.                 }
  1171. #endif
  1172.  
  1173.         /* this command prints the entire current text to the
  1174.         terminal's printer; at the end it displays the top of the text */
  1175. #ifdef SLAVE_PRINTER
  1176. #define SLAVE_PRINTER_ON  "\033\133\065\151"
  1177. #define SLAVE_PRINTER_OFF "\033\133\064\151"
  1178.             
  1179.             if (Check_User_Input("PS")) {
  1180.                 printf ("%s",SLAVE_PRINTER_ON);
  1181.                 printf("\f");                   /* Form feed for new page */
  1182.                 HText_scrollTop(HTMainText);
  1183.                 while(HText_canScrollDown(HTMainText)) {
  1184.                     HText_scrollDown(HTMainText);
  1185.                     }
  1186.                 printf("\f");  /* Form feed for new page */
  1187.                 printf ("%s",SLAVE_PRINTER_OFF);
  1188.                 HText_scrollTop(HTMainText);
  1189.                 return;
  1190.                 }
  1191.             
  1192. #endif
  1193.         break;
  1194.  
  1195.  
  1196.  
  1197.  
  1198.     case 'Q':                                /* Quit program ? */
  1199.         if (Check_User_Input("QUIT")) {
  1200. #ifdef VM
  1201.             if (HTHistory_canBacktrack()){  /* Means one level only */
  1202.                 HTLoadAnchor(HTHistory_backtrack());
  1203.                 goto ret;
  1204.             } else {
  1205.                 exit(0);        /* On last level, exit */
  1206.             }
  1207. #endif
  1208. /*     JFG 9/7/92, following a complaint of 'q' mis-typed for '1'.
  1209.     JFG Then made optional because I hate it !!!
  1210.     TBL made it only affect remote logged on users. 921122 */
  1211.  
  1212.             if (HTClientHost && (strcasecomp(this_word, "quit") != 0) ) {
  1213.             printf ("\n  Please type \"quit\" in full to leave www.\n");
  1214.             goto ret;
  1215.             }
  1216.  
  1217.             exit(0);
  1218.         }
  1219.         break;
  1220.  
  1221.  
  1222.  
  1223.  
  1224.     case 'R':
  1225. #ifdef VM
  1226.         if (Check_User_Input("RETURN"))    /* Means quit program */
  1227.                 exit(0);
  1228. #endif        
  1229.         if (Check_User_Input("RECALL")){
  1230.         int  recall_node_num;
  1231.         if (!HTHistory_canBacktrack()){    /* No nodes to recall */
  1232.             printf("\n  No other documents to recall.\n");
  1233.             goto ret;
  1234.         }
  1235.         /* Is there a previous node number to recall, or does the user just require
  1236.         a list of nodes visited? */
  1237.         
  1238.         if (next_word) {
  1239.             if ((recall_node_num = atoi(next_word)) > 0)  /* Good parameter */
  1240.                 HTLoadAnchor(HTHistory_recall(recall_node_num));
  1241.             else
  1242.                 Error_Selection();
  1243.         }
  1244.         else 
  1245.             History_List();
  1246.         
  1247.         goto ret;
  1248.  
  1249.         } else if (Check_User_Input("REFRESH")){
  1250.             HText_select(HTMainText);        /* Refresh screen */
  1251.         goto ret;
  1252.         }
  1253.         break;
  1254.  
  1255.     case 'S':                    /* TBL 921009 */
  1256.         if (Check_User_Input("SOURCE")) {       /* Apply to source */
  1257.             if (!next_word) goto ret;    /* Should refresh as source @@@ */
  1258.  
  1259.             HTDiag = YES;            /* Load, print source */
  1260.             this_word = next_word;        /* Move up one word */
  1261.             next_word = strtok (NULL, " \t\n\r");
  1262.             this_command = the_choice + (this_word - choice);
  1263.             other_words = the_choice + (next_word - choice);
  1264.             goto loop;        /* Go treat as before */
  1265.         }
  1266.         break;
  1267.     case 'T':
  1268.         if (Check_User_Input("TOP")) {   /* Return to top  */
  1269.             HText_scrollTop(HTMainText);
  1270.             goto ret;
  1271.             }
  1272.         break;
  1273.  
  1274.     case 'U':
  1275.         if (Check_User_Input("UP")) {   /* Scroll up one page  */
  1276.             HText_scrollUp(HTMainText);
  1277.             goto ret;
  1278.             }
  1279.         break;
  1280.  
  1281.     case 'V':
  1282.         if (Check_User_Input("VERBOSE")) {   /* Switch verbose mode  */
  1283.             WWW_TraceFlag = ! WWW_TraceFlag;
  1284.             printf ("\n  Verbose mode %s.\n", WWW_TraceFlag ? "ON" : "OFF");
  1285.             goto ret;
  1286.             }
  1287.         break;
  1288.     
  1289. #ifdef GOT_PIPE
  1290.     case '>':
  1291.     case '|':
  1292.     if (!HTClientHost) {    /* Local only!!!! */
  1293.         char * address = HTAnchor_address((HTAnchor*)HTMainAnchor);
  1294.         char * command;
  1295.         int result;
  1296.         
  1297.         command  = (char *) malloc(
  1298.             strlen(address)+strlen(this_command)+30);
  1299. #ifdef VM
  1300.         sprintf(command, "PIPE CMS WWW %s \"%s\" | %s",
  1301.         /* Note format is | > */ 
  1302. #else
  1303.         sprintf(command, "www %s \"%s\" %s", 
  1304. #endif
  1305.                HTDiag ? "-source" : "-n -na -p", address, this_command);
  1306.         result = system(command);
  1307.         if (result) printf("  %s  returns %d\n", command, result);
  1308.         free(command);
  1309.         free(address);
  1310.         goto ret;
  1311.     }
  1312. #endif
  1313.  
  1314. #ifdef GOT_SYSTEM
  1315.     case '!':
  1316.     if (!HTClientHost) {    /* Local only!!!!!!! */
  1317.         int result;
  1318.         result = system(strchr(this_command, '!') + 1);
  1319.         if (result) printf("  %s  returns %d\n",
  1320.             strchr(this_command, '!') + 1, result);
  1321.         goto ret;
  1322.         }
  1323. #endif
  1324.     
  1325.     default:
  1326.         break;
  1327.  
  1328.     }    /* Switch on 1st character */
  1329.     
  1330.  
  1331.     if (is_index && *this_word) {  /* No commands, search keywords */
  1332.         if (HTSearch(this_command + (this_word - choice), HTMainAnchor))
  1333.         HTHistory_record((HTAnchor*)HTMainAnchor);
  1334.     } else {             
  1335.         Error_Selection();
  1336.     }
  1337.  
  1338. ret:    free (the_choice);
  1339.     return;
  1340.     
  1341.     }    /* Get user selection */
  1342. } /* Selection_Prompt */
  1343.  
  1344.  
  1345. /* *end HTBrowse.c* */